#ifndef AVALON_DIRECTORY_HPP
#define AVALON_DIRECTORY_HPP
#include <map>
#include <vector>
#include <boost/signals2.hpp>
#include <boost/thread/mutex.hpp>
#include "Avalon/Base/Mask.hpp"
#include "Avalon/ServiceLocator/DirectoryEntry.hpp"

namespace Avalon {
namespace ServiceLocator {

  /*! \class Directory
   *  \brief Stores DirectoryEntries and permissions.
   *  \author Kamal Mansouri <kranar@hotmail.com>
   */
  class Directory : public DirectoryEntry {
    public:

      /*! \struct Permission
       *  \brief Enumerates Directory permissions.
       */
      struct Permission : public Mask<Permission, 2> {

        //! Read permission.
        static const Permission READ;

        //! Write permission.
        static const Permission WRITE;

        //! READ | WRITE.
        static const Permission READ_WRITE;

        //! Constructs the NONE enumeration.
        Permission() {}

        //! Constructs a Permission.
        /*!
          \param value The integral value.
        */
        Permission(ValueType value) : Mask<Permission, 2>(value) {}
      };

      //! Signals that a DirectoryEntry was added or removed.
      /*!
        \param tag The Tag of the DirectoryEntry.
        \param added <code>true</code> iff the DirectoryEntry was added.
      */
      typedef boost::signals2::signal<void (const Tag&, bool)>
        EntryChangedSignal;

      //! Constructs a Directory.
      /*!
        \param tag The Tag identifying the directory.
      */
      Directory(const Tag& tag);

      //! Constructs a Directory.
      /*!
        \param tag The Tag identifying the directory.
        \param entries The entries within the directory.
        \param permissions The permissions to this directory.
      */
      Directory(const Tag& tag, const std::vector<Tag>& entries,
        const std::map<unsigned int, Permission>& permissions);

      virtual ~Directory();

      virtual Type GetType();

      virtual Tag GetTag();

      //! Returns the list of DirectoryEntry Tags within this directory.
      std::vector<Tag> GetEntries();

      //! Returns the Permissions for this Directory.
      std::map<unsigned int, Permission> GetPermissions();

      //! Connects to the EntryChangedSignal.
      /*!
        \param slot The slot to connect.
        \param entries A snapshot of this Directory's entries.
        \return The <i>slot</i>'s connection to the signal.
      */
      boost::signals2::connection ConnectEntryChangedSignal(
        const EntryChangedSignal::slot_type& slot);

      //! Connects to the EntryChangedSignal.
      /*!
        \param slot The slot to connect.
        \param entries A snapshot of this Directory's entries.
        \return The <i>slot</i>'s connection to the signal.
      */
      boost::signals2::connection ConnectEntryChangedSignal(
        const EntryChangedSignal::slot_type& slot, std::vector<Tag>* entries);

    protected:
      virtual void Shuttle(Serialization::DataShuttle* shuttle,
        unsigned int version);

    private:
      friend class Serialization::DataShuttle;
      friend class ServiceLocatorClient;
      boost::mutex m_mutex;
      Tag m_tag;
      std::vector<Tag> m_entries;
      std::map<unsigned int, Permission> m_permissions;
      EntryChangedSignal m_entryChangedSignal;

      Directory();
      void AddEntry(const Tag& entry);
      void RemoveEntry(const Tag& entry);
  };
}
}

#endif // AVALON_DIRECTORY_HPP
